// This file is part of Keepass2Android, Copyright 2025 Philipp Crocoll.
//
//   Keepass2Android is free software: you can redistribute it and/or modify
//   it under the terms of the GNU General Public License as published by
//   the Free Software Foundation, either version 3 of the License, or
//   (at your option) any later version.
//
//   Keepass2Android is distributed in the hope that it will be useful,
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//   GNU General Public License for more details.
//
//   You should have received a copy of the GNU General Public License
//   along with Keepass2Android.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
#if !NoNet
using FluentFTP;
using static Kp2aBusinessLogic.Io.SmbFileStorage;
#endif
using System.Text;

using Android.App;
using Android.Content;
using Android.Content.Res;
using Android.OS;
using Android.Preferences;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Google.Android.Material.Dialog;
using Java.IO;
using keepass2android.Io;
using keepass2android;
#if !EXCLUDE_JAVAFILESTORAGE
using Keepass2android.Javafilestorage;
#endif
using KeePassLib.Serialization;
using KeePassLib.Utility;


namespace keepass2android
{
  public class FileSelectHelper
  {
    public static string ConvertFilenameToIocPath(string filename)
    {
      if ((filename != null) && (filename.StartsWith("file://")))
      {
        filename = filename.Substring(7);
        filename = Java.Net.URLDecoder.Decode(filename);
      }
      return filename;
    }

    private readonly Activity _activity;
    private readonly bool _isForSave;
    private readonly int _requestCode;
    private readonly string _schemeSeparator = "://";
    private bool _tryGetPermanentAccess;

    private const int SftpModeSpinnerPasswd = 0;
    private const int SftpModeSpinnerPubKey = 1;
    private const int SftpModeSpinnerCustomKey = 2;

    private const int SftpKeySpinnerCreateNewIdx = 0;

    public string DefaultExtension { get; set; }

    public FileSelectHelper(Activity activity, bool isForSave, bool tryGetPermanentAccess, int requestCode)
    {
      _activity = activity;
      _isForSave = isForSave;
      _requestCode = requestCode;
      _tryGetPermanentAccess = tryGetPermanentAccess;
    }

    private void ShowSftpDialog(Activity activity, Util.FileSelectedHandler onStartBrowse, Action onCancel, string defaultPath)
    {
#if !EXCLUDE_JAVAFILESTORAGE && !NoNet
      MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity);
      View dlgContents = activity.LayoutInflater.Inflate(Resource.Layout.sftpcredentials, null);
      var ctx = activity.ApplicationContext;
      var fileStorage = new Keepass2android.Javafilestorage.SftpStorage(ctx);

      LinearLayout addNewBtn = dlgContents.FindViewById<LinearLayout>(Resource.Id.sftp_add_key_group);
      Button deleteBtn = dlgContents.FindViewById<Button>(Resource.Id.sftp_delete_key_button);
      EditText keyNameTxt = dlgContents.FindViewById<EditText>(Resource.Id.sftp_key_name);
      EditText keyContentTxt = dlgContents.FindViewById<EditText>(Resource.Id.sftp_key_content);

      var keySpinner = dlgContents.FindViewById<Spinner>(Resource.Id.sftp_key_names);
      var keyNamesAdapter = new ArrayAdapter(ctx, Android.Resource.Layout.SimpleSpinnerDropDownItem, new List<string>());
      UpdatePrivateKeyNames(keyNamesAdapter, fileStorage, ctx);
      keyNamesAdapter.SetDropDownViewResource(Android.Resource.Layout.SimpleSpinnerDropDownItem);
      keySpinner.Adapter = keyNamesAdapter;
      keySpinner.SetSelection(SftpKeySpinnerCreateNewIdx);

      keySpinner.ItemSelected += (sender, args) =>
      {
        if (keySpinner.SelectedItemPosition == SftpKeySpinnerCreateNewIdx)
        {
          keyNameTxt.Text = "";
          keyContentTxt.Text = "";
          addNewBtn.Visibility = ViewStates.Visible;
          deleteBtn.Visibility = ViewStates.Gone;
        }
        else
        {
          addNewBtn.Visibility = ViewStates.Gone;
          deleteBtn.Visibility = ViewStates.Visible;
        }
      };

      var authModeSpinner = dlgContents.FindViewById<Spinner>(Resource.Id.sftp_auth_mode_spinner);
      dlgContents.FindViewById<Button>(Resource.Id.send_public_key_button).Click += (sender, args) =>
      {
        string pub_filename = fileStorage.CreateKeyPair();

        Intent sendIntent = new Intent();
        sendIntent.SetAction(Intent.ActionSend);
        sendIntent.PutExtra(Intent.ExtraText, System.IO.File.ReadAllText(pub_filename));

        sendIntent.PutExtra(Intent.ExtraSubject, "Keepass2Android sftp public key");
        sendIntent.SetType("text/plain");
        activity.StartActivity(Intent.CreateChooser(sendIntent, "Send public key to..."));
      };

      dlgContents.FindViewById<Button>(Resource.Id.sftp_save_key_button).Click += (sender, args) =>
      {
        string keyName = keyNameTxt.Text;
        string keyContent = keyContentTxt.Text;

        string toastMsg = null;
        MessageSeverity severity = MessageSeverity.Info;
        if (!string.IsNullOrEmpty(keyName) && !string.IsNullOrEmpty(keyContent))
        {
          try
          {
            fileStorage.SavePrivateKeyContent(keyName, keyContent);
            keyNameTxt.Text = "";
            keyContentTxt.Text = "";
            toastMsg = ctx.GetString(Resource.String.private_key_saved);
          }
          catch (Exception e)
          {
            toastMsg = ctx.GetString(Resource.String.private_key_save_failed,
                      new Java.Lang.Object[] { Util.GetErrorMessage(e) });
            severity = MessageSeverity.Error;

          }
        }
        else
        {
          toastMsg = ctx.GetString(Resource.String.private_key_info);
        }

        if (toastMsg != null)
        {
          App.Kp2a.ShowMessage(_activity, toastMsg, severity);
        }

        UpdatePrivateKeyNames(keyNamesAdapter, fileStorage, ctx);
        keySpinner.SetSelection(ResolveKeySpinnerSelection(keyNamesAdapter, keyName));
      };

      dlgContents.FindViewById<Button>(Resource.Id.sftp_delete_key_button).Click += (sender, args) =>
      {
        int selectedKey = dlgContents.FindViewById<Spinner>(Resource.Id.sftp_key_names).SelectedItemPosition;
        string keyName = ResolveSelectedKeyName(keyNamesAdapter, selectedKey);
        if (!string.IsNullOrEmpty(keyName))
        {
          bool deleted = fileStorage.DeleteCustomKey(keyName);

          int msgId = deleted ? Resource.String.private_key_delete : Resource.String.private_key_delete_failed;
          string msg = ctx.GetString(msgId, new Java.Lang.Object[] { keyName });
          App.Kp2a.ShowMessage(_activity, msg, deleted ? MessageSeverity.Info : MessageSeverity.Error);

          UpdatePrivateKeyNames(keyNamesAdapter, fileStorage, ctx);
          keySpinner.SetSelection(SftpKeySpinnerCreateNewIdx);
        }
      };

      authModeSpinner.ItemSelected += (sender, args) =>
      {
        var passwordBox = dlgContents.FindViewById<EditText>(Resource.Id.sftp_password);
        var publicKeyButton = dlgContents.FindViewById<Button>(Resource.Id.send_public_key_button);
        var keyfileGroup = dlgContents.FindViewById<LinearLayout>(Resource.Id.sftp_keyfile_group);

        switch (authModeSpinner.SelectedItemPosition)
        {
          case SftpModeSpinnerPasswd:
            passwordBox.Visibility = ViewStates.Visible;
            publicKeyButton.Visibility = ViewStates.Gone;
            keyfileGroup.Visibility = ViewStates.Gone;
            break;
          case SftpModeSpinnerPubKey:
            passwordBox.Visibility = ViewStates.Gone;
            publicKeyButton.Visibility = ViewStates.Visible;
            keyfileGroup.Visibility = ViewStates.Gone;
            break;
          case SftpModeSpinnerCustomKey:
            passwordBox.Visibility = ViewStates.Gone;
            publicKeyButton.Visibility = ViewStates.Gone;
            keyfileGroup.Visibility = ViewStates.Visible;
            break;
        }
      };

      if (!defaultPath.EndsWith(_schemeSeparator))
      {
        SftpStorage.ConnectionInfo ci = fileStorage.SplitStringToConnectionInfo(defaultPath);
        dlgContents.FindViewById<EditText>(Resource.Id.sftp_host).Text = ci.Host;
        dlgContents.FindViewById<EditText>(Resource.Id.sftp_port).Text = ci.Port.ToString();
        dlgContents.FindViewById<EditText>(Resource.Id.sftp_user).Text = ci.Username;
        dlgContents.FindViewById<EditText>(Resource.Id.sftp_password).Text = ci.Password;
        dlgContents.FindViewById<EditText>(Resource.Id.sftp_key_name).Text = ci.KeyName;
        dlgContents.FindViewById<EditText>(Resource.Id.sftp_key_passphrase).Text = ci.KeyPassphrase;
        dlgContents.FindViewById<EditText>(Resource.Id.sftp_initial_dir).Text = ci.LocalPath;
        if (ci.ConnectTimeoutSec != SftpStorage.UnsetSftpConnectTimeout)
        {
          dlgContents.FindViewById<EditText>(Resource.Id.sftp_connect_timeout).Text = ci.ConnectTimeoutSec.ToString();
        }

        if (ci.ConfigOpts.Contains(SftpStorage.SshCfgKex))
        {
          dlgContents.FindViewById<EditText>(Resource.Id.sftp_kex).Text = ci.ConfigOpts[SftpStorage.SshCfgKex].ToString();
        }
        if (ci.ConfigOpts.Contains(SftpStorage.SshCfgServerHostKey))
        {
          dlgContents.FindViewById<EditText>(Resource.Id.sftp_shk).Text = ci.ConfigOpts[SftpStorage.SshCfgServerHostKey].ToString();
        }

        if (!string.IsNullOrEmpty(ci.Password))
        {
          authModeSpinner.SetSelection(SftpModeSpinnerPasswd);
        }
        else if (!string.IsNullOrEmpty(ci.KeyName))
        {
          authModeSpinner.SetSelection(SftpModeSpinnerCustomKey);
          keySpinner.SetSelection(ResolveKeySpinnerSelection(keyNamesAdapter, ci.KeyName));
        }
        else
        {
          authModeSpinner.SetSelection(SftpModeSpinnerPubKey);
        }

      }

      builder.SetView(dlgContents);
      builder.SetPositiveButton(Android.Resource.String.Ok, (sender, args) =>
      {
        int idx = 0;
        string host = dlgContents.FindViewById<EditText>(Resource.Id.sftp_host).Text;
        string portText = dlgContents.FindViewById<EditText>(Resource.Id.sftp_port).Text;
        int port = SftpStorage.DefaultSftpPort;
        if (!string.IsNullOrEmpty(portText))
          int.TryParse(portText, out port);
        string user = dlgContents.FindViewById<EditText>(Resource.Id.sftp_user).Text;

        string password = null;
        string keyName = null, keyPassphrase = null;
        switch (dlgContents.FindViewById<Spinner>(Resource.Id.sftp_auth_mode_spinner).SelectedItemPosition)
        {
          case SftpModeSpinnerPasswd:
            password = dlgContents.FindViewById<EditText>(Resource.Id.sftp_password).Text;
            break;
          case SftpModeSpinnerPubKey:
            break;
          case SftpModeSpinnerCustomKey:
            keyName = ResolveSelectedKeyName(keyNamesAdapter, keySpinner.SelectedItemPosition);
            keyPassphrase = dlgContents.FindViewById<EditText>(Resource.Id.sftp_key_passphrase).Text;
            break;
        }

        string initialPath = dlgContents.FindViewById<EditText>(Resource.Id.sftp_initial_dir).Text;
        if (string.IsNullOrEmpty(initialPath))
          initialPath = "/";
        string connectTimeoutText = dlgContents.FindViewById<EditText>(Resource.Id.sftp_connect_timeout).Text;
        int connectTimeout = SftpStorage.UnsetSftpConnectTimeout;
        if (!string.IsNullOrEmpty(connectTimeoutText))
        {
          int.TryParse(connectTimeoutText, out connectTimeout);
        }
        string kexAlgorithms = dlgContents.FindViewById<EditText>(Resource.Id.sftp_kex).Text;
        string shkAlgorithms = dlgContents.FindViewById<EditText>(Resource.Id.sftp_shk).Text;

        string sftpPath = fileStorage.BuildFullPath(
                  host, port, initialPath, user, password, connectTimeout, keyName, keyPassphrase,
                  kexAlgorithms, shkAlgorithms);

        onStartBrowse(sftpPath);
      });
      EventHandler<DialogClickEventArgs> evtH = new EventHandler<DialogClickEventArgs>((sender, e) => onCancel());

      builder.SetNegativeButton(Android.Resource.String.Cancel, evtH);
      builder.SetTitle(activity.GetString(Resource.String.enter_sftp_login_title));
      builder.SetCancelable(false);
      Dialog dialog = builder.Create();

      dialog.Show();
#endif
    }

#if !EXCLUDE_JAVAFILESTORAGE && !NoNet
    private void UpdatePrivateKeyNames(ArrayAdapter dataView, SftpStorage storage, Context ctx)
    {
      dataView.Clear();
      dataView.Add(ctx.GetString(Resource.String.private_key_create_new));
      foreach (string keyName in storage.GetCustomKeyNames())
        dataView.Add(keyName);
    }

    private int ResolveKeySpinnerSelection(ArrayAdapter dataView, string keyName)
    {
      int idx = -1;
      for (int i = 0; i < dataView.Count; i++)
      {
        string itemName = dataView.GetItem(i).ToString();
        if (string.Equals(keyName, itemName))
        {
          idx = i;
          break;
        }
      }
      return idx < 0 ? SftpKeySpinnerCreateNewIdx : idx;
    }

    private string ResolveSelectedKeyName(ArrayAdapter dataView, int selectedItem)
    {
      if (selectedItem != SftpKeySpinnerCreateNewIdx && selectedItem > 0 && selectedItem < dataView.Count)
        return dataView.GetItem(selectedItem).ToString();
      else
        return null;
    }
#endif

    private void ShowHttpDialog(Activity activity, Util.FileSelectedHandler onStartBrowse, Action onCancel, string defaultPath)
    {
#if !EXCLUDE_JAVAFILESTORAGE && !NoNet
      MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity);
      View dlgContents = activity.LayoutInflater.Inflate(Resource.Layout.httpcredentials, null);
      if (!defaultPath.EndsWith(_schemeSeparator))
      {
        var webdavStorage = CreateWebdavStorage(activity);
        var connInfo = webdavStorage.SplitStringToConnectionInfo(defaultPath);
        dlgContents.FindViewById<EditText>(Resource.Id.http_url).Text = connInfo.Url;
        dlgContents.FindViewById<EditText>(Resource.Id.http_user).Text = connInfo.Username;
        dlgContents.FindViewById<EditText>(Resource.Id.http_password).Text = connInfo.Password;


      }
      builder.SetView(dlgContents);
      builder.SetPositiveButton(Android.Resource.String.Ok,
                                (sender, args) =>
                                {
                                  string host = dlgContents.FindViewById<EditText>(Resource.Id.http_url).Text;

                                  string user = dlgContents.FindViewById<EditText>(Resource.Id.http_user).Text;
                                  string password = dlgContents.FindViewById<EditText>(Resource.Id.http_password).Text;

                                  string scheme = defaultPath.Substring(0, defaultPath.IndexOf(_schemeSeparator, StringComparison.Ordinal));
                                  if (host.Contains(_schemeSeparator) == false)
                                    host = scheme + _schemeSeparator + host;
                                  string httpPath = CreateWebdavStorage(activity).BuildFullPath(host, user,
                                                                                                        password);
                                  onStartBrowse(httpPath);
                                });
      EventHandler<DialogClickEventArgs> evtH = new EventHandler<DialogClickEventArgs>((sender, e) => onCancel());

      builder.SetNegativeButton(Android.Resource.String.Cancel, evtH);
      builder.SetTitle(activity.GetString(Resource.String.enter_http_login_title));
      builder.SetCancelable(false);
      Dialog dialog = builder.Create();

      dialog.Show();
#endif
    }


    private void ShowSmbDialog(Activity activity, Util.FileSelectedHandler onStartBrowse, Action onCancel, string defaultPath)
    {
#if !EXCLUDE_JAVAFILESTORAGE && !NoNet
      MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity);
      View dlgContents = activity.LayoutInflater.Inflate(Resource.Layout.smbcredentials, null);
      if (!defaultPath.EndsWith(_schemeSeparator))
      {
        SmbConnectionInfo ci = new SmbConnectionInfo(new IOConnectionInfo() { Path = defaultPath });

        dlgContents.FindViewById<EditText>(Resource.Id.smb_url).Text = ci.GetPathWithoutCredentials();
        dlgContents.FindViewById<EditText>(Resource.Id.smb_domain).Text = ci.Domain;
        dlgContents.FindViewById<EditText>(Resource.Id.smb_user).Text = ci.Username;
        dlgContents.FindViewById<EditText>(Resource.Id.smb_password).Text = ci.Password;


      }
      builder.SetView(dlgContents);
      builder.SetPositiveButton(Android.Resource.String.Ok,
                                (sender, args) =>
                                {
                                  string url = dlgContents.FindViewById<EditText>(Resource.Id.smb_url).Text;

                                  string user = dlgContents.FindViewById<EditText>(Resource.Id.smb_user).Text;
                                  string password = dlgContents.FindViewById<EditText>(Resource.Id.smb_password).Text;
                                  string domain = dlgContents.FindViewById<EditText>(Resource.Id.smb_domain).Text;

                                  string fullPath = SmbConnectionInfo.FromUrlAndCredentials(url, user, password, domain).ToPath();
                                  onStartBrowse(fullPath);
                                });
      builder.SetCancelable(false);

      EventHandler<DialogClickEventArgs> evtH = new EventHandler<DialogClickEventArgs>((sender, e) => onCancel());

      builder.SetNegativeButton(Android.Resource.String.Cancel, evtH);
      builder.SetTitle(activity.GetString(Resource.String.enter_smb_login_title));
      Dialog dialog = builder.Create();

      dialog.Show();
#endif
    }
#if !NoNet
    private static WebDavStorage CreateWebdavStorage(Activity activity)
    {
      return new WebDavStorage(App.Kp2a.CertificateErrorHandler, App.Kp2a.WebDavChunkedUploadSize, App.Context);
    }
#endif
    private void ShowFtpDialog(Activity activity, Util.FileSelectedHandler onStartBrowse, Action onCancel, string defaultPath)
    {
#if !NoNet
      MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity);
      View dlgContents = activity.LayoutInflater.Inflate(Resource.Layout.ftpcredentials, null);
      if (!defaultPath.EndsWith(_schemeSeparator))
      {
        var connection = NetFtpFileStorage.ConnectionSettings.FromIoc(IOConnectionInfo.FromPath(defaultPath));
        dlgContents.FindViewById<EditText>(Resource.Id.ftp_user).Text = connection.Username;
        dlgContents.FindViewById<EditText>(Resource.Id.ftp_password).Text = connection.Password;
        dlgContents.FindViewById<Spinner>(Resource.Id.ftp_encryption).SetSelection((int)connection.EncryptionMode);

        var uri = NetFtpFileStorage.IocToUri(IOConnectionInfo.FromPath(defaultPath));
        string pathAndQuery = uri.PathAndQuery;

        var host = uri.Host;
        var localPath = WebUtility.UrlDecode(pathAndQuery);


        if (!uri.IsDefaultPort)
        {
          dlgContents.FindViewById<EditText>(Resource.Id.ftp_port).Text = uri.Port.ToString();
        }
        dlgContents.FindViewById<EditText>(Resource.Id.ftp_host).Text = host;
        dlgContents.FindViewById<EditText>(Resource.Id.ftp_initial_dir).Text = localPath;


      }
      builder.SetView(dlgContents);
      builder.SetPositiveButton(Android.Resource.String.Ok,
                                (sender, args) =>
                                {
                                  string host = dlgContents.FindViewById<EditText>(Resource.Id.ftp_host).Text;
                                  string portText = dlgContents.FindViewById<EditText>(Resource.Id.ftp_port).Text;
                                  FtpEncryptionMode encryption =
                                            (FtpEncryptionMode)dlgContents.FindViewById<Spinner>(Resource.Id.ftp_encryption).SelectedItemPosition;
                                  int port = NetFtpFileStorage.GetDefaultPort(encryption);
                                  if (!string.IsNullOrEmpty(portText))
                                    int.TryParse(portText, out port);
                                  string user = dlgContents.FindViewById<EditText>(Resource.Id.ftp_user).Text;
                                  string password = dlgContents.FindViewById<EditText>(Resource.Id.ftp_password).Text;
                                  string initialPath = dlgContents.FindViewById<EditText>(Resource.Id.ftp_initial_dir).Text;
                                  string ftpPath = new NetFtpFileStorage(_activity, App.Kp2a, () => false)
                                            .BuildFullPath(host, port, initialPath, user, password, encryption);
                                  onStartBrowse(ftpPath);
                                });
      EventHandler<DialogClickEventArgs> evtH = new EventHandler<DialogClickEventArgs>((sender, e) => onCancel());

      builder.SetNegativeButton(Android.Resource.String.Cancel, evtH);
      builder.SetTitle(activity.GetString(Resource.String.enter_ftp_login_title));
      builder.SetCancelable(false);
      Dialog dialog = builder.Create();

      dialog.Show();
#endif
    }


    private void ShowMegaDialog(Activity activity, Util.FileSelectedHandler onStartBrowse, Action onCancel, string defaultPath)
    {
#if !NoNet
      var settings = MegaFileStorage.GetAccountSettings(activity);
      MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity);
      View dlgContents = activity.LayoutInflater.Inflate(Resource.Layout.megacredentials, null);
      if (!defaultPath.EndsWith(_schemeSeparator))
      {
        string user = "";
        string password = "";
        if (!defaultPath.EndsWith(_schemeSeparator))
        {
          user = MegaFileStorage.GetAccount(defaultPath);
          if (!settings.PasswordByUsername.TryGetValue(user, out password))
            password = "";
          dlgContents.FindViewById<EditText>(Resource.Id.mega_user).Enabled = false;

        }
        dlgContents.FindViewById<EditText>(Resource.Id.mega_user).Text = user;
        dlgContents.FindViewById<EditText>(Resource.Id.mega_password).Text = password;

      }

      var userView = ((AutoCompleteTextView)dlgContents.FindViewById(Resource.Id.mega_user));
      userView.Adapter = new ArrayAdapter(activity, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, settings.PasswordByUsername.Keys.ToArray());

      userView.TextChanged += (sender, args) =>
      {
        if (userView.Text != null && settings.PasswordByUsername.TryGetValue(userView.Text, out string pwd))
        {
          dlgContents.FindViewById<EditText>(Resource.Id.mega_password).Text = pwd;
        }
      };
      builder.SetCancelable(false);
      builder.SetView(dlgContents);
      builder.SetPositiveButton(Android.Resource.String.Ok,
                                (sender, args) =>
                                {
                                  string user = dlgContents.FindViewById<EditText>(Resource.Id.mega_user).Text;
                                  string password = dlgContents.FindViewById<EditText>(Resource.Id.mega_password).Text;
                                  //store the credentials in the mega credentials store:


                                  settings.PasswordByUsername[user] = password;

                                  MegaFileStorage.UpdateAccountSettings(settings, activity);

                                  onStartBrowse(MegaFileStorage.ProtocolId + "://" + user);
                                });
      EventHandler<DialogClickEventArgs> evtH = new EventHandler<DialogClickEventArgs>((sender, e) => onCancel());

      builder.SetNegativeButton(Android.Resource.String.Cancel, evtH);
      builder.SetTitle(activity.GetString(Resource.String.enter_mega_login_title));
      builder.SetCancelable(false);
      Dialog dialog = builder.Create();

      dialog.Show();
#endif
    }



    public void PerformManualFileSelect(string defaultPath)
    {
      if (defaultPath.StartsWith("sftp://"))
        ShowSftpDialog(_activity, ReturnFileOrStartFileChooser, ReturnCancel, defaultPath);
      else if ((defaultPath.StartsWith("ftp://")) || (defaultPath.StartsWith("ftps://")))
        ShowFtpDialog(_activity, ReturnFileOrStartFileChooser, ReturnCancel, defaultPath);
      else if ((defaultPath.StartsWith("http://")) || (defaultPath.StartsWith("https://")))
        ShowHttpDialog(_activity, ReturnFileOrStartFileChooser, ReturnCancel, defaultPath);
      else if ((defaultPath.StartsWith("smb://")))
        ShowSmbDialog(_activity, ReturnFileOrStartFileChooser, ReturnCancel, defaultPath);
      else if (defaultPath.StartsWith("owncloud://"))
        ShowOwncloudDialog(_activity, ReturnFileOrStartFileChooser, ReturnCancel, defaultPath, "owncloud");
      else if (defaultPath.StartsWith("nextcloud://"))
        ShowOwncloudDialog(_activity, ReturnFileOrStartFileChooser, ReturnCancel, defaultPath, "nextcloud");
      else if (defaultPath.StartsWith("mega://"))
        ShowMegaDialog(_activity, ReturnFileOrStartFileChooser, ReturnCancel, defaultPath);
      else
      {
        Func<string, Dialog, bool> onOpen = OnOpenButton;
        Util.ShowFilenameDialog(_activity,
                                !_isForSave ? onOpen : null,
                                _isForSave ? onOpen : null,
                                ReturnCancel,
                                false,
                                defaultPath,
                                _activity.GetString(Resource.String.enter_filename_details_url),
                                _requestCode)
        ;
      }
    }

    private void ShowOwncloudDialog(Activity activity, Util.FileSelectedHandler onStartBrowse, Action onCancel, string defaultPath, string subtype)
    {
#if !EXCLUDE_JAVAFILESTORAGE && !NoNet
      MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity);
      View dlgContents = activity.LayoutInflater.Inflate(Resource.Layout.owncloudcredentials, null);
      builder.SetView(dlgContents);

      builder.SetPositiveButton(Android.Resource.String.Ok,
                                (sender, args) =>
                                {
                                  string host = dlgContents.FindViewById<EditText>(Resource.Id.owncloud_url).Text;

                                  string user = dlgContents.FindViewById<EditText>(Resource.Id.http_user).Text;
                                  string password = dlgContents.FindViewById<EditText>(Resource.Id.http_password).Text;

                                  string scheme = defaultPath.Substring(0, defaultPath.IndexOf(_schemeSeparator, StringComparison.Ordinal));
                                  if (host.Contains(_schemeSeparator) == false)
                                    host = scheme + _schemeSeparator + host;
                                  string httpPath = CreateWebdavStorage(activity).BuildFullPath(WebDavFileStorage.Owncloud2Webdav(host, subtype == "owncloud" ? WebDavFileStorage.owncloudPrefix : WebDavFileStorage.nextcloudPrefix), user,
                                                                                                        password);
                                  onStartBrowse(httpPath);
                                });
      EventHandler<DialogClickEventArgs> evtH = new EventHandler<DialogClickEventArgs>((sender, e) => onCancel());

      builder.SetNegativeButton(Android.Resource.String.Cancel, evtH);
      builder.SetTitle(activity.GetString(subtype == "owncloud" ? Resource.String.enter_owncloud_login_title : Resource.String.enter_nextcloud_login_title));
      builder.SetCancelable(false);
      Dialog dialog = builder.Create();
      dlgContents.FindViewById<EditText>(Resource.Id.owncloud_url).SetHint(subtype == "owncloud" ? Resource.String.hint_owncloud_url : Resource.String.hint_nextcloud_url);
      dialog.Show();
#endif

    }

    private bool ReturnFileOrStartFileChooser(string filename)
    {
      string filenameWithoutProt = filename;
      if (filenameWithoutProt.Contains(_schemeSeparator))
      {
        filenameWithoutProt =
            filenameWithoutProt.Substring(filenameWithoutProt.IndexOf(_schemeSeparator, StringComparison.Ordinal) + 3);
      }

      int lastSlashPos = filenameWithoutProt.LastIndexOf('/');
      int lastDotPos = filenameWithoutProt.LastIndexOf('.');
      if ((lastSlashPos < 0) //no slash, probably only a server address (my.server.com)
          || (lastSlashPos >= lastDotPos)) //no dot after last slash or == in case neither / nor .
      {
        //looks like a folder.
        return StartFileChooser(filename);
      }
      //looks like a file
      IocSelected(null, IOConnectionInfo.FromPath(filename));
      return true;
    }

    private void ReturnCancel()
    {
      if (OnCancel != null)
        OnCancel(this, null);
    }


    protected void ShowFilenameWarning(string fileName, Action onUserWantsToContinue, Action onUserWantsToCorrect)
    {
      new MaterialAlertDialogBuilder(_activity)
              .SetPositiveButton(Resource.String.Continue, delegate { onUserWantsToContinue(); })
              .SetMessage(Resource.String.NoFilenameWarning)
              .SetCancelable(false)
              .SetNegativeButton(Android.Resource.String.Cancel, delegate { onUserWantsToCorrect(); })
              .Create()
              .Show();

    }
    private bool OnOpenButton(string filename, Dialog dialog)
    {

      IOConnectionInfo ioc = new IOConnectionInfo
      {
        Path = filename
      };

      // Make sure file name exists
      if (filename.Length == 0)
      {
        App.Kp2a.ShowMessage(_activity,
                        Resource.String.error_filename_required,
                         MessageSeverity.Error);
        return false;
      }


      int lastSlashPos = filename.LastIndexOf('/');
      int lastDotPos = filename.LastIndexOf('.');
      if (lastSlashPos >= lastDotPos) //no dot after last slash or == in case neither / nor .
      {
        ShowFilenameWarning(filename, () => { IocSelected(null, ioc); dialog.Dismiss(); }, () => { /* don't do anything, leave dialog open, let user try again*/ });
        //signal that the dialog should be kept open
        return false;
      }

      IFileStorage fileStorage;
      try
      {
        fileStorage = App.Kp2a.GetFileStorage(ioc);
      }
      catch (NoFileStorageFoundException)
      {
        App.Kp2a.ShowMessage(_activity,
                        "Unexpected scheme in " + filename,
                         MessageSeverity.Error);
        return false;
      }

      if (_isForSave && ioc.IsLocalFile())
      {
        // Try to create the file
        Java.IO.File file = new Java.IO.File(filename);
        try
        {
          Java.IO.File parent = file.ParentFile;

          if (parent == null || (parent.Exists() && !parent.IsDirectory))
          {
            App.Kp2a.ShowMessage(_activity,
                            Resource.String.error_invalid_path,
                             MessageSeverity.Error);
            return false;
          }

          if (!parent.Exists())
          {
            // Create parent dircetory
            if (!parent.Mkdirs())
            {
              App.Kp2a.ShowMessage(_activity,
                              Resource.String.error_could_not_create_parent,
                               MessageSeverity.Error);
              return false;

            }
          }
          System.IO.File.Create(filename).Dispose();

        }
        catch (Java.IO.IOException ex)
        {
          App.Kp2a.ShowMessage(
              _activity,
              _activity.GetText(Resource.String.error_file_not_create) + " "
              + ex.LocalizedMessage,
               MessageSeverity.Error);
          return false;
        }

      }
      if (fileStorage.RequiresCredentials(ioc))
      {
        Util.QueryCredentials(ioc, iocResult => IocSelected(null, iocResult), _activity);
      }
      else
      {
        IocSelected(null, ioc);
      }

      return true;
    }

    private void IocSelected(Context context, IOConnectionInfo ioc)
    {
      if (OnOpen != null)
        OnOpen(context, ioc);
    }

    public bool StartFileChooser(string defaultPath)
    {
#if !EXCLUDE_FILECHOOSER
      string fileProviderAuthority = FileChooserFileProvider.TheAuthority;
      if (defaultPath.StartsWith("file://"))
      {
        fileProviderAuthority = _activity.PackageName + ".android-filechooser.localfile";
      }
      Intent i = Keepass2android.Kp2afilechooser.Kp2aFileChooserBridge.GetLaunchFileChooserIntent(_activity, fileProviderAuthority,
                                                                                                  defaultPath);


      if (_isForSave)
      {
        i.PutExtra("group.pals.android.lib.ui.filechooser.FileChooserActivity.save_dialog", true);
        string ext;
        if (!string.IsNullOrEmpty(DefaultExtension))
        {
          ext = DefaultExtension;
        }
        else
        {
          ext = UrlUtil.GetExtension(defaultPath);
        }
        if ((ext != String.Empty) && (ext.Contains("?") == false))
          i.PutExtra("group.pals.android.lib.ui.filechooser.FileChooserActivity.default_file_ext", ext);
      }
      _activity.StartActivityForResult(i, _requestCode);

#else
			App.Kp2a.ShowMessage(LocaleManager.LocalizedAppContext, "File chooser is excluded!",  MessageSeverity.Error);
#endif
      return true;
    }

    public event EventHandler OnCancel;

    public event EventHandler<IOConnectionInfo> OnOpen;

    public static bool CanEditIoc(IOConnectionInfo ioc)
    {
      return ioc.Path.StartsWith("http")
             || ioc.Path.StartsWith("ftp")
             || ioc.Path.StartsWith("sftp")
             || ioc.Path.StartsWith("mega");

    }

    public bool HandleActivityResult(Activity activity, int requestCode, Result resultCode, Intent data)
    {
      if (requestCode != _requestCode)
        return false;

      if (resultCode == KeePass.ExitFileStorageSelectionOk)
      {
        string protocolId = data.GetStringExtra("protocolId");
        if (protocolId == "content")
        {
          Util.ShowBrowseDialog(activity, _requestCode, _isForSave, _tryGetPermanentAccess);
        }
        else
        {
          App.Kp2a.GetFileStorage(protocolId).StartSelectFile(
                  new FileStorageSetupInitiatorActivity(activity, (i, result, arg3) => HandleActivityResult(activity, i, result, arg3), s => PerformManualFileSelect(s)),
                  _isForSave,
                  _requestCode,
                  protocolId);
        }
      }

      if (resultCode == Result.Ok)
      {

        if (data.Data.Scheme == "content")
        {
          if ((int)Build.VERSION.SdkInt >= 19)
          {
            //try to take persistable permissions
            try
            {
              Kp2aLog.Log("TakePersistableUriPermission");
              var takeFlags = data.Flags
                      & (ActivityFlags.GrantReadUriPermission
                      | ActivityFlags.GrantWriteUriPermission);
              activity.ContentResolver.TakePersistableUriPermission(data.Data, takeFlags);
            }
            catch (Exception e)
            {
              Kp2aLog.Log(e.ToString());
            }

          }
        }


        string filename = Util.IntentToFilename(data, activity);
        if (filename == null)
          filename = data.DataString;

        bool fileExists = data.GetBooleanExtra("group.pals.android.lib.ui.filechooser.FileChooserActivity.result_file_exists", true);

        if (fileExists)
        {
          var ioc = new IOConnectionInfo { Path = ConvertFilenameToIocPath(filename) };
          IocSelected(activity, ioc);
        }
        else
        {
          var task = new CreateNewFilename(App.Kp2a, new ActionOnOperationFinished(App.Kp2a, (success, messageOrFilename, newActivity) =>
              {
                if (!success)
                {
                  App.Kp2a.ShowMessage(newActivity, messageOrFilename, MessageSeverity.Error);
                  return;
                }
                var ioc = new IOConnectionInfo { Path = ConvertFilenameToIocPath(messageOrFilename) };
                IocSelected(newActivity, ioc);

              }), filename);

          new BlockingOperationStarter(App.Kp2a, task).Run();
        }

      }


      if (resultCode == (Result)FileStorageResults.FileUsagePrepared)
      {
        var ioc = new IOConnectionInfo();
        Util.SetIoConnectionFromIntent(ioc, data);
        IocSelected(null, ioc);
      }
      if (resultCode == (Result)FileStorageResults.FileChooserPrepared)
      {
        IOConnectionInfo ioc = new IOConnectionInfo();
        Util.SetIoConnectionFromIntent(ioc, data);
        StartFileChooser(ioc.Path);

      }
      return true;

    }
  }
}